mobbdev 0.0.83 → 0.0.85
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.mjs +599 -162
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -94,8 +94,8 @@ var errorMessages = {
|
|
|
94
94
|
missingCxProjectName: `project name ${chalk.bold(
|
|
95
95
|
"(--cx-project-name)"
|
|
96
96
|
)} is needed if you're using checkmarx`,
|
|
97
|
-
|
|
98
|
-
"(--
|
|
97
|
+
missingUrl: `url ${chalk.bold(
|
|
98
|
+
"(--url)"
|
|
99
99
|
)} is needed if you're adding an SCM token`,
|
|
100
100
|
invalidScmType: `SCM type ${chalk.bold(
|
|
101
101
|
"(--scm-type)"
|
|
@@ -173,7 +173,6 @@ var CliError = class extends Error {
|
|
|
173
173
|
};
|
|
174
174
|
|
|
175
175
|
// src/features/analysis/index.ts
|
|
176
|
-
import { Octokit as Octokit3 } from "@octokit/core";
|
|
177
176
|
import chalk4 from "chalk";
|
|
178
177
|
import Configstore from "configstore";
|
|
179
178
|
import Debug10 from "debug";
|
|
@@ -237,23 +236,33 @@ import { v4 as uuidv4 } from "uuid";
|
|
|
237
236
|
import { gql } from "graphql-request";
|
|
238
237
|
var UPDATE_SCM_TOKEN = gql`
|
|
239
238
|
mutation updateScmToken(
|
|
240
|
-
$
|
|
239
|
+
$scmType: String!
|
|
240
|
+
$url: String!
|
|
241
241
|
$token: String!
|
|
242
242
|
$org: String
|
|
243
243
|
$username: String
|
|
244
244
|
$refreshToken: String
|
|
245
245
|
) {
|
|
246
246
|
updateScmToken(
|
|
247
|
-
|
|
247
|
+
scmType: $scmType
|
|
248
|
+
url: $url
|
|
248
249
|
token: $token
|
|
249
250
|
org: $org
|
|
250
251
|
username: $username
|
|
251
252
|
refreshToken: $refreshToken
|
|
252
253
|
) {
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
254
|
+
__typename
|
|
255
|
+
... on ScmAccessTokenUpdateSuccess {
|
|
256
|
+
token
|
|
257
|
+
}
|
|
258
|
+
... on InvalidScmTypeError {
|
|
259
|
+
status
|
|
260
|
+
error
|
|
261
|
+
}
|
|
262
|
+
... on BadScmCredentials {
|
|
263
|
+
status
|
|
264
|
+
error
|
|
265
|
+
}
|
|
257
266
|
}
|
|
258
267
|
}
|
|
259
268
|
`;
|
|
@@ -368,10 +377,20 @@ var ME = gql2`
|
|
|
368
377
|
me {
|
|
369
378
|
id
|
|
370
379
|
email
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
380
|
+
scmConfigs {
|
|
381
|
+
id
|
|
382
|
+
isBroker
|
|
383
|
+
orgId
|
|
384
|
+
refreshToken
|
|
385
|
+
scmType
|
|
386
|
+
scmUrl
|
|
387
|
+
scmUsername
|
|
388
|
+
token
|
|
389
|
+
tokenLastUpdate
|
|
390
|
+
userId
|
|
391
|
+
scmOrg
|
|
392
|
+
isTokenAvailable
|
|
393
|
+
}
|
|
375
394
|
}
|
|
376
395
|
}
|
|
377
396
|
`;
|
|
@@ -456,6 +475,17 @@ var GET_FIX = gql2`
|
|
|
456
475
|
}
|
|
457
476
|
}
|
|
458
477
|
`;
|
|
478
|
+
var GET_FIXES = gql2`
|
|
479
|
+
query getFixes($filters: fix_bool_exp!) {
|
|
480
|
+
fixes: fix(where: $filters) {
|
|
481
|
+
issueType
|
|
482
|
+
id
|
|
483
|
+
patchAndQuestions {
|
|
484
|
+
patch
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
`;
|
|
459
489
|
var GET_VUL_BY_NODES_METADATA = gql2`
|
|
460
490
|
query getVulByNodesMetadata(
|
|
461
491
|
$filters: [vulnerability_report_issue_code_node_bool_exp!]
|
|
@@ -466,6 +496,7 @@ var GET_VUL_BY_NODES_METADATA = gql2`
|
|
|
466
496
|
where: {
|
|
467
497
|
_or: $filters
|
|
468
498
|
vulnerabilityReportIssue: {
|
|
499
|
+
fixId: { _is_null: false }
|
|
469
500
|
vulnerabilityReportId: { _eq: $vulnerabilityReportId }
|
|
470
501
|
}
|
|
471
502
|
}
|
|
@@ -478,6 +509,35 @@ var GET_VUL_BY_NODES_METADATA = gql2`
|
|
|
478
509
|
fixId
|
|
479
510
|
}
|
|
480
511
|
}
|
|
512
|
+
fixablePrVuls: vulnerability_report_issue_aggregate(
|
|
513
|
+
where: {
|
|
514
|
+
fixId: { _is_null: false }
|
|
515
|
+
vulnerabilityReportId: { _eq: $vulnerabilityReportId }
|
|
516
|
+
codeNodes: { _or: $filters }
|
|
517
|
+
}
|
|
518
|
+
) {
|
|
519
|
+
aggregate {
|
|
520
|
+
count
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
nonFixablePrVuls: vulnerability_report_issue_aggregate(
|
|
524
|
+
where: {
|
|
525
|
+
fixId: { _is_null: true }
|
|
526
|
+
vulnerabilityReportId: { _eq: $vulnerabilityReportId }
|
|
527
|
+
codeNodes: { _or: $filters }
|
|
528
|
+
}
|
|
529
|
+
) {
|
|
530
|
+
aggregate {
|
|
531
|
+
count
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
totalScanVulnerabilities: vulnerability_report_issue_aggregate(
|
|
535
|
+
where: { vulnerabilityReportId: { _eq: $vulnerabilityReportId } }
|
|
536
|
+
) {
|
|
537
|
+
aggregate {
|
|
538
|
+
count
|
|
539
|
+
}
|
|
540
|
+
}
|
|
481
541
|
}
|
|
482
542
|
`;
|
|
483
543
|
|
|
@@ -565,10 +625,7 @@ function subscribe(query, variables, callback, wsClientOptions) {
|
|
|
565
625
|
import { z as z2 } from "zod";
|
|
566
626
|
var UpdateScmTokenZ = z2.object({
|
|
567
627
|
updateScmToken: z2.object({
|
|
568
|
-
|
|
569
|
-
gitHubAccessToken: z2.string().nullable(),
|
|
570
|
-
gitlabAccessToken: z2.string().nullable(),
|
|
571
|
-
adoAccessToken: z2.string().nullable()
|
|
628
|
+
token: z2.string()
|
|
572
629
|
})
|
|
573
630
|
});
|
|
574
631
|
var UploadFieldsZ = z2.object({
|
|
@@ -694,15 +751,17 @@ var GetAnalysisQueryZ = z2.object({
|
|
|
694
751
|
})
|
|
695
752
|
})
|
|
696
753
|
});
|
|
697
|
-
var
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
patch: z2.string()
|
|
703
|
-
})
|
|
754
|
+
var FixDataZ = z2.object({
|
|
755
|
+
issueType: z2.string(),
|
|
756
|
+
id: z2.string(),
|
|
757
|
+
patchAndQuestions: z2.object({
|
|
758
|
+
patch: z2.string()
|
|
704
759
|
})
|
|
705
760
|
});
|
|
761
|
+
var GetFixQueryZ = z2.object({
|
|
762
|
+
fix_by_pk: FixDataZ
|
|
763
|
+
});
|
|
764
|
+
var GetFixesQueryZ = z2.object({ fixes: z2.array(FixDataZ) });
|
|
706
765
|
var VulnerabilityReportIssueCodeNodeZ = z2.object({
|
|
707
766
|
vulnerabilityReportIssueId: z2.string(),
|
|
708
767
|
path: z2.string(),
|
|
@@ -712,7 +771,22 @@ var VulnerabilityReportIssueCodeNodeZ = z2.object({
|
|
|
712
771
|
})
|
|
713
772
|
});
|
|
714
773
|
var GetVulByNodesMetadataZ = z2.object({
|
|
715
|
-
vulnerabilityReportIssueCodeNodes: z2.array(VulnerabilityReportIssueCodeNodeZ)
|
|
774
|
+
vulnerabilityReportIssueCodeNodes: z2.array(VulnerabilityReportIssueCodeNodeZ),
|
|
775
|
+
nonFixablePrVuls: z2.object({
|
|
776
|
+
aggregate: z2.object({
|
|
777
|
+
count: z2.number()
|
|
778
|
+
})
|
|
779
|
+
}),
|
|
780
|
+
fixablePrVuls: z2.object({
|
|
781
|
+
aggregate: z2.object({
|
|
782
|
+
count: z2.number()
|
|
783
|
+
})
|
|
784
|
+
}),
|
|
785
|
+
totalScanVulnerabilities: z2.object({
|
|
786
|
+
aggregate: z2.object({
|
|
787
|
+
count: z2.number()
|
|
788
|
+
})
|
|
789
|
+
})
|
|
716
790
|
});
|
|
717
791
|
|
|
718
792
|
// src/features/analysis/graphql/gql.ts
|
|
@@ -803,9 +877,10 @@ var GQLClient = class {
|
|
|
803
877
|
}
|
|
804
878
|
}
|
|
805
879
|
async updateScmToken(args) {
|
|
806
|
-
const {
|
|
880
|
+
const { scmType, url, token, org, username, refreshToken } = args;
|
|
807
881
|
const updateScmTokenResult = await this._client.request(UPDATE_SCM_TOKEN, {
|
|
808
|
-
|
|
882
|
+
scmType,
|
|
883
|
+
url,
|
|
809
884
|
token,
|
|
810
885
|
org,
|
|
811
886
|
username,
|
|
@@ -826,7 +901,6 @@ var GQLClient = class {
|
|
|
826
901
|
const filters = hunks.map((hunk) => {
|
|
827
902
|
const filter = {
|
|
828
903
|
path: { _eq: hunk.path },
|
|
829
|
-
vulnerabilityReportIssue: { fixId: { _is_null: false } },
|
|
830
904
|
_or: hunk.ranges.map(({ endLine, startLine }) => ({
|
|
831
905
|
startLine: { _gte: startLine, _lte: endLine },
|
|
832
906
|
endLine: { _gte: startLine, _lte: endLine }
|
|
@@ -850,10 +924,20 @@ var GQLClient = class {
|
|
|
850
924
|
[vulnerabilityReportIssueCodeNode.vulnerabilityReportIssueId]: vulnerabilityReportIssueCodeNode
|
|
851
925
|
};
|
|
852
926
|
}, {});
|
|
927
|
+
const nonFixablePrVuls = parsedGetVulByNodesMetadataRes.nonFixablePrVuls.aggregate.count;
|
|
928
|
+
const fixablePrVuls = parsedGetVulByNodesMetadataRes.fixablePrVuls.aggregate.count;
|
|
929
|
+
const totalScanVulnerabilities = parsedGetVulByNodesMetadataRes.totalScanVulnerabilities.aggregate.count;
|
|
930
|
+
const vulnerabilitiesOutsidePr = totalScanVulnerabilities - nonFixablePrVuls - fixablePrVuls;
|
|
931
|
+
const totalPrVulnerabilities = nonFixablePrVuls + fixablePrVuls;
|
|
853
932
|
return {
|
|
854
933
|
vulnerabilityReportIssueCodeNodes: Object.values(
|
|
855
934
|
uniqueVulByNodesMetadata
|
|
856
|
-
)
|
|
935
|
+
),
|
|
936
|
+
nonFixablePrVuls,
|
|
937
|
+
fixablePrVuls,
|
|
938
|
+
totalScanVulnerabilities,
|
|
939
|
+
vulnerabilitiesOutsidePr,
|
|
940
|
+
totalPrVulnerabilities
|
|
857
941
|
};
|
|
858
942
|
}
|
|
859
943
|
async digestVulnerabilityReport({
|
|
@@ -959,9 +1043,19 @@ var GQLClient = class {
|
|
|
959
1043
|
);
|
|
960
1044
|
return GetFixQueryZ.parse(res);
|
|
961
1045
|
}
|
|
1046
|
+
async getFixes(fixIds) {
|
|
1047
|
+
const res = await this._client.request(
|
|
1048
|
+
GET_FIXES,
|
|
1049
|
+
{
|
|
1050
|
+
filters: { id: { _in: fixIds } }
|
|
1051
|
+
}
|
|
1052
|
+
);
|
|
1053
|
+
return GetFixesQueryZ.parse(res);
|
|
1054
|
+
}
|
|
962
1055
|
};
|
|
963
1056
|
|
|
964
1057
|
// src/features/analysis/handle_finished_analysis.ts
|
|
1058
|
+
import { Octokit as Octokit3 } from "@octokit/core";
|
|
965
1059
|
import Debug4 from "debug";
|
|
966
1060
|
import parseDiff from "parse-diff";
|
|
967
1061
|
import { z as z9 } from "zod";
|
|
@@ -1402,9 +1496,9 @@ async function getGithubBlameRanges({ ref, gitHubUrl, path: path9 }, options) {
|
|
|
1402
1496
|
return res.repository.object.blame.ranges.map((range) => ({
|
|
1403
1497
|
startingLine: range.startingLine,
|
|
1404
1498
|
endingLine: range.endingLine,
|
|
1405
|
-
email: range.commit.author.user
|
|
1406
|
-
name: range.commit.author.user
|
|
1407
|
-
login: range.commit.author.user
|
|
1499
|
+
email: range.commit.author.user?.email || "",
|
|
1500
|
+
name: range.commit.author.user?.name || "",
|
|
1501
|
+
login: range.commit.author.user?.login || ""
|
|
1408
1502
|
}));
|
|
1409
1503
|
}
|
|
1410
1504
|
async function createPr({
|
|
@@ -1509,6 +1603,9 @@ var UPDATE_COMMENT_PATH = "PATCH /repos/{owner}/{repo}/pulls/comments/{comment_i
|
|
|
1509
1603
|
var GET_PR_COMMENTS_PATH = "GET /repos/{owner}/{repo}/pulls/{pull_number}/comments";
|
|
1510
1604
|
var GET_PR_COMMENT_PATH = "GET /repos/{owner}/{repo}/pulls/comments/{comment_id}";
|
|
1511
1605
|
var GET_PR = "GET /repos/{owner}/{repo}/pulls/{pull_number}";
|
|
1606
|
+
var POST_GENERAL_PR_COMMENT = "POST /repos/{owner}/{repo}/issues/{issue_number}/comments";
|
|
1607
|
+
var GET_GENERAL_PR_COMMENTS = "GET /repos/{owner}/{repo}/issues/{issue_number}/comments";
|
|
1608
|
+
var DELETE_GENERAL_PR_COMMENT = "DELETE /repos/{owner}/{repo}/issues/comments/{comment_id}";
|
|
1512
1609
|
var CREATE_OR_UPDATE_A_REPOSITORY_SECRET = "PUT /repos/{owner}/{repo}/actions/secrets/{secret_name}";
|
|
1513
1610
|
var GET_A_REPOSITORY_PUBLIC_KEY = "GET /repos/{owner}/{repo}/actions/secrets/public-key";
|
|
1514
1611
|
|
|
@@ -1540,6 +1637,15 @@ function createOrUpdateRepositorySecret(client, params) {
|
|
|
1540
1637
|
function getARepositoryPublicKey(client, params) {
|
|
1541
1638
|
return client.request(GET_A_REPOSITORY_PUBLIC_KEY, params);
|
|
1542
1639
|
}
|
|
1640
|
+
function postGeneralPrComment(client, params) {
|
|
1641
|
+
return client.request(POST_GENERAL_PR_COMMENT, params);
|
|
1642
|
+
}
|
|
1643
|
+
function getGeneralPrComments(client, params) {
|
|
1644
|
+
return client.request(GET_GENERAL_PR_COMMENTS, params);
|
|
1645
|
+
}
|
|
1646
|
+
function deleteGeneralPrComment(client, params) {
|
|
1647
|
+
return client.request(DELETE_GENERAL_PR_COMMENT, params);
|
|
1648
|
+
}
|
|
1543
1649
|
|
|
1544
1650
|
// src/features/analysis/scm/gitlab.ts
|
|
1545
1651
|
import querystring from "node:querystring";
|
|
@@ -1881,7 +1987,7 @@ var isValidBranchName = async (branchName) => {
|
|
|
1881
1987
|
var FixesZ = z6.array(z6.object({ fixId: z6.string(), diff: z6.string() })).nonempty();
|
|
1882
1988
|
|
|
1883
1989
|
// src/features/analysis/scm/scm.ts
|
|
1884
|
-
function
|
|
1990
|
+
function getCloudScmLibTypeFromUrl(url) {
|
|
1885
1991
|
if (!url) {
|
|
1886
1992
|
return void 0;
|
|
1887
1993
|
}
|
|
@@ -1898,19 +2004,92 @@ function getScmLibTypeFromUrl(url) {
|
|
|
1898
2004
|
}
|
|
1899
2005
|
return void 0;
|
|
1900
2006
|
}
|
|
2007
|
+
function getScmTypeFromScmLibType(scmLibType) {
|
|
2008
|
+
if (scmLibType === "GITLAB" /* GITLAB */) {
|
|
2009
|
+
return "GitLab" /* GitLab */;
|
|
2010
|
+
}
|
|
2011
|
+
if (scmLibType === "GITHUB" /* GITHUB */) {
|
|
2012
|
+
return "GitHub" /* GitHub */;
|
|
2013
|
+
}
|
|
2014
|
+
if (scmLibType === "ADO" /* ADO */) {
|
|
2015
|
+
return "Ado" /* Ado */;
|
|
2016
|
+
}
|
|
2017
|
+
throw new Error(`unknown scm lib type: ${scmLibType}`);
|
|
2018
|
+
}
|
|
2019
|
+
function getScmLibTypeFromScmType(scmType) {
|
|
2020
|
+
if (scmType === "GitLab" /* GitLab */) {
|
|
2021
|
+
return "GITLAB" /* GITLAB */;
|
|
2022
|
+
}
|
|
2023
|
+
if (scmType === "GitHub" /* GitHub */) {
|
|
2024
|
+
return "GITHUB" /* GITHUB */;
|
|
2025
|
+
}
|
|
2026
|
+
if (scmType === "Ado" /* Ado */) {
|
|
2027
|
+
return "ADO" /* ADO */;
|
|
2028
|
+
}
|
|
2029
|
+
throw new Error(`unknown scm type: ${scmType}`);
|
|
2030
|
+
}
|
|
2031
|
+
function getScmConfig({
|
|
2032
|
+
url,
|
|
2033
|
+
scmConfigs,
|
|
2034
|
+
includeOrgTokens = true
|
|
2035
|
+
}) {
|
|
2036
|
+
const filteredScmConfigs = scmConfigs.filter((scm) => {
|
|
2037
|
+
const urlObject = new URL(url);
|
|
2038
|
+
const configUrl = new URL(scm.scmUrl);
|
|
2039
|
+
return (
|
|
2040
|
+
//if we the user does an ADO oauth flow then the token is saved for dev.azure.com but
|
|
2041
|
+
//sometimes the user uses the url dev.azure.com and sometimes the url visualstudio.com
|
|
2042
|
+
//so we need to check both
|
|
2043
|
+
(urlObject.hostname === configUrl.hostname || urlObject.hostname.endsWith(".visualstudio.com") && configUrl.hostname === "dev.azure.com") && urlObject.protocol === configUrl.protocol && urlObject.port === configUrl.port
|
|
2044
|
+
);
|
|
2045
|
+
});
|
|
2046
|
+
const scmOrgConfig = filteredScmConfigs.find((scm) => scm.orgId && scm.token);
|
|
2047
|
+
if (scmOrgConfig && includeOrgTokens) {
|
|
2048
|
+
return {
|
|
2049
|
+
id: scmOrgConfig.id,
|
|
2050
|
+
accessToken: scmOrgConfig.token || void 0,
|
|
2051
|
+
scmLibType: getScmLibTypeFromScmType(scmOrgConfig.scmType),
|
|
2052
|
+
scmOrg: scmOrgConfig.scmOrg || void 0
|
|
2053
|
+
};
|
|
2054
|
+
}
|
|
2055
|
+
const scmUserConfig = filteredScmConfigs.find(
|
|
2056
|
+
(scm) => scm.userId && scm.token
|
|
2057
|
+
);
|
|
2058
|
+
if (scmUserConfig) {
|
|
2059
|
+
return {
|
|
2060
|
+
id: scmUserConfig.id,
|
|
2061
|
+
accessToken: scmUserConfig.token || void 0,
|
|
2062
|
+
scmLibType: getScmLibTypeFromScmType(scmUserConfig.scmType),
|
|
2063
|
+
scmOrg: scmUserConfig.scmOrg || void 0
|
|
2064
|
+
};
|
|
2065
|
+
}
|
|
2066
|
+
const type2 = getCloudScmLibTypeFromUrl(url);
|
|
2067
|
+
if (type2) {
|
|
2068
|
+
return {
|
|
2069
|
+
id: void 0,
|
|
2070
|
+
accessToken: void 0,
|
|
2071
|
+
scmLibType: type2,
|
|
2072
|
+
scmOrg: void 0
|
|
2073
|
+
};
|
|
2074
|
+
}
|
|
2075
|
+
return {
|
|
2076
|
+
id: void 0,
|
|
2077
|
+
accessToken: void 0,
|
|
2078
|
+
scmLibType: void 0,
|
|
2079
|
+
scmOrg: void 0
|
|
2080
|
+
};
|
|
2081
|
+
}
|
|
1901
2082
|
async function scmCanReachRepo({
|
|
1902
2083
|
repoUrl,
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
adoToken,
|
|
2084
|
+
scmType,
|
|
2085
|
+
accessToken,
|
|
1906
2086
|
scmOrg
|
|
1907
2087
|
}) {
|
|
1908
2088
|
try {
|
|
1909
|
-
const scmLibType = getScmLibTypeFromUrl(repoUrl);
|
|
1910
2089
|
await SCMLib.init({
|
|
1911
2090
|
url: repoUrl,
|
|
1912
|
-
accessToken
|
|
1913
|
-
scmType:
|
|
2091
|
+
accessToken,
|
|
2092
|
+
scmType: getScmLibTypeFromScmType(scmType),
|
|
1914
2093
|
scmOrg
|
|
1915
2094
|
});
|
|
1916
2095
|
return true;
|
|
@@ -1961,7 +2140,7 @@ var SCMLib = class {
|
|
|
1961
2140
|
if (!this.accessToken) {
|
|
1962
2141
|
return trimmedUrl;
|
|
1963
2142
|
}
|
|
1964
|
-
const scmLibType =
|
|
2143
|
+
const scmLibType = this.getScmLibType();
|
|
1965
2144
|
if (scmLibType === "ADO" /* ADO */) {
|
|
1966
2145
|
return `https://${this.accessToken}@${trimmedUrl.toLowerCase().replace("https://", "")}`;
|
|
1967
2146
|
}
|
|
@@ -2088,6 +2267,9 @@ var AdoSCMLib = class extends SCMLib {
|
|
|
2088
2267
|
repoUrl: this.url
|
|
2089
2268
|
});
|
|
2090
2269
|
}
|
|
2270
|
+
getScmLibType() {
|
|
2271
|
+
return "ADO" /* ADO */;
|
|
2272
|
+
}
|
|
2091
2273
|
getAuthHeaders() {
|
|
2092
2274
|
if (this.accessToken) {
|
|
2093
2275
|
if (getAdoTokenType(this.accessToken) === "OAUTH" /* OAUTH */) {
|
|
@@ -2191,6 +2373,15 @@ var AdoSCMLib = class extends SCMLib {
|
|
|
2191
2373
|
getPr() {
|
|
2192
2374
|
throw new Error("Method not implemented.");
|
|
2193
2375
|
}
|
|
2376
|
+
postGeneralPrComment() {
|
|
2377
|
+
throw new Error("Method not implemented.");
|
|
2378
|
+
}
|
|
2379
|
+
getGeneralPrComments() {
|
|
2380
|
+
throw new Error("Method not implemented.");
|
|
2381
|
+
}
|
|
2382
|
+
deleteGeneralPrComment() {
|
|
2383
|
+
throw new Error("Method not implemented.");
|
|
2384
|
+
}
|
|
2194
2385
|
};
|
|
2195
2386
|
var GitlabSCMLib = class extends SCMLib {
|
|
2196
2387
|
async createSubmitRequest(targetBranchName, sourceBranchName, title, body) {
|
|
@@ -2249,6 +2440,9 @@ var GitlabSCMLib = class extends SCMLib {
|
|
|
2249
2440
|
repoUrl: this.url
|
|
2250
2441
|
});
|
|
2251
2442
|
}
|
|
2443
|
+
getScmLibType() {
|
|
2444
|
+
return "GITLAB" /* GITLAB */;
|
|
2445
|
+
}
|
|
2252
2446
|
getAuthHeaders() {
|
|
2253
2447
|
if (this?.accessToken?.startsWith("glpat-")) {
|
|
2254
2448
|
return {
|
|
@@ -2362,6 +2556,15 @@ var GitlabSCMLib = class extends SCMLib {
|
|
|
2362
2556
|
getPr() {
|
|
2363
2557
|
throw new Error("Method not implemented.");
|
|
2364
2558
|
}
|
|
2559
|
+
postGeneralPrComment() {
|
|
2560
|
+
throw new Error("Method not implemented.");
|
|
2561
|
+
}
|
|
2562
|
+
getGeneralPrComments() {
|
|
2563
|
+
throw new Error("Method not implemented.");
|
|
2564
|
+
}
|
|
2565
|
+
deleteGeneralPrComment() {
|
|
2566
|
+
throw new Error("Method not implemented.");
|
|
2567
|
+
}
|
|
2365
2568
|
};
|
|
2366
2569
|
var GithubSCMLib = class extends SCMLib {
|
|
2367
2570
|
// we don't always need a url, what's important is that we have an access token
|
|
@@ -2512,6 +2715,9 @@ var GithubSCMLib = class extends SCMLib {
|
|
|
2512
2715
|
}
|
|
2513
2716
|
return getGithubBranchList(this.accessToken, this.url);
|
|
2514
2717
|
}
|
|
2718
|
+
getScmLibType() {
|
|
2719
|
+
return "GITHUB" /* GITHUB */;
|
|
2720
|
+
}
|
|
2515
2721
|
getAuthHeaders() {
|
|
2516
2722
|
if (this.accessToken) {
|
|
2517
2723
|
return { authorization: `Bearer ${this.accessToken}` };
|
|
@@ -2627,12 +2833,58 @@ var GithubSCMLib = class extends SCMLib {
|
|
|
2627
2833
|
pull_number: prNumber
|
|
2628
2834
|
});
|
|
2629
2835
|
}
|
|
2836
|
+
async postGeneralPrComment(params, auth) {
|
|
2837
|
+
const { prNumber, body } = params;
|
|
2838
|
+
if (!this.url) {
|
|
2839
|
+
console.error("no url");
|
|
2840
|
+
throw new Error("no url");
|
|
2841
|
+
}
|
|
2842
|
+
const oktoKit = auth ? new Octokit2({ auth: auth.authToken }) : this.oktokit;
|
|
2843
|
+
const { owner, repo } = parseGithubOwnerAndRepo(this.url);
|
|
2844
|
+
return await postGeneralPrComment(oktoKit, {
|
|
2845
|
+
issue_number: prNumber,
|
|
2846
|
+
owner,
|
|
2847
|
+
repo,
|
|
2848
|
+
body
|
|
2849
|
+
});
|
|
2850
|
+
}
|
|
2851
|
+
async getGeneralPrComments(params, auth) {
|
|
2852
|
+
const { prNumber } = params;
|
|
2853
|
+
if (!this.url) {
|
|
2854
|
+
console.error("no url");
|
|
2855
|
+
throw new Error("no url");
|
|
2856
|
+
}
|
|
2857
|
+
const oktoKit = auth ? new Octokit2({ auth: auth.authToken }) : this.oktokit;
|
|
2858
|
+
const { owner, repo } = parseGithubOwnerAndRepo(this.url);
|
|
2859
|
+
return await getGeneralPrComments(oktoKit, {
|
|
2860
|
+
issue_number: prNumber,
|
|
2861
|
+
owner,
|
|
2862
|
+
repo
|
|
2863
|
+
});
|
|
2864
|
+
}
|
|
2865
|
+
async deleteGeneralPrComment({ commentId }, auth) {
|
|
2866
|
+
if (!this.url) {
|
|
2867
|
+
console.error("no url");
|
|
2868
|
+
throw new Error("no url");
|
|
2869
|
+
}
|
|
2870
|
+
const oktoKit = auth ? new Octokit2({ auth: auth.authToken }) : this.oktokit;
|
|
2871
|
+
const { owner, repo } = parseGithubOwnerAndRepo(this.url);
|
|
2872
|
+
return deleteGeneralPrComment(oktoKit, {
|
|
2873
|
+
owner,
|
|
2874
|
+
repo,
|
|
2875
|
+
comment_id: commentId
|
|
2876
|
+
});
|
|
2877
|
+
}
|
|
2630
2878
|
};
|
|
2631
2879
|
var StubSCMLib = class extends SCMLib {
|
|
2632
2880
|
async createSubmitRequest(_targetBranchName, _sourceBranchName, _title, _body) {
|
|
2633
2881
|
console.error("createSubmitRequest() not implemented");
|
|
2634
2882
|
throw new Error("createSubmitRequest() not implemented");
|
|
2635
2883
|
}
|
|
2884
|
+
getScmLibType() {
|
|
2885
|
+
console.error("getScmLibType() not implemented");
|
|
2886
|
+
throw new Error("getScmLibType() not implemented");
|
|
2887
|
+
}
|
|
2636
2888
|
getAuthHeaders() {
|
|
2637
2889
|
console.error("getAuthHeaders() not implemented");
|
|
2638
2890
|
throw new Error("getAuthHeaders() not implemented");
|
|
@@ -2709,6 +2961,15 @@ var StubSCMLib = class extends SCMLib {
|
|
|
2709
2961
|
console.error("getPr() not implemented");
|
|
2710
2962
|
throw new Error("getPr() not implemented");
|
|
2711
2963
|
}
|
|
2964
|
+
postGeneralPrComment() {
|
|
2965
|
+
throw new Error("Method not implemented.");
|
|
2966
|
+
}
|
|
2967
|
+
getGeneralPrComments() {
|
|
2968
|
+
throw new Error("Method not implemented.");
|
|
2969
|
+
}
|
|
2970
|
+
deleteGeneralPrComment() {
|
|
2971
|
+
throw new Error("Method not implemented.");
|
|
2972
|
+
}
|
|
2712
2973
|
};
|
|
2713
2974
|
|
|
2714
2975
|
// src/features/analysis/scm/ado.ts
|
|
@@ -3160,7 +3421,7 @@ var AdoAuthResultZ = z8.object({
|
|
|
3160
3421
|
});
|
|
3161
3422
|
|
|
3162
3423
|
// src/features/analysis/scm/constants.ts
|
|
3163
|
-
var MOBB_ICON_IMG = "https://
|
|
3424
|
+
var MOBB_ICON_IMG = "https://app.mobb.ai/gh-action/Logo_Rounded_Icon.svg";
|
|
3164
3425
|
var COMMIT_FIX_SVG = `https://app.mobb.ai/gh-action/commit-button.svg`;
|
|
3165
3426
|
|
|
3166
3427
|
// src/features/analysis/scm/utils/get_issue_type.ts
|
|
@@ -3275,6 +3536,13 @@ function getCommitUrl(params) {
|
|
|
3275
3536
|
})}/commit?${searchParams.toString()}`;
|
|
3276
3537
|
}
|
|
3277
3538
|
|
|
3539
|
+
// src/features/analysis/utils/by_key.ts
|
|
3540
|
+
function keyBy(array, keyBy2) {
|
|
3541
|
+
return array.reduce((acc, item) => {
|
|
3542
|
+
return { ...acc, [item[keyBy2]]: item };
|
|
3543
|
+
}, {});
|
|
3544
|
+
}
|
|
3545
|
+
|
|
3278
3546
|
// src/features/analysis/utils/calculate_ranges.ts
|
|
3279
3547
|
function calculateRanges(integers) {
|
|
3280
3548
|
if (integers.length === 0) {
|
|
@@ -3302,7 +3570,10 @@ function calculateRanges(integers) {
|
|
|
3302
3570
|
|
|
3303
3571
|
// src/features/analysis/handle_finished_analysis.ts
|
|
3304
3572
|
var debug4 = Debug4("mobbdev:handle-finished-analysis");
|
|
3573
|
+
var contactUsMarkdown = `For specific requests [contact us](https://mobb.ai/contact) and we'll do the most to answer your need quickly.`;
|
|
3305
3574
|
var commitFixButton = (commitUrl) => `<a href="${commitUrl}"><img src=${COMMIT_FIX_SVG}></a>`;
|
|
3575
|
+
var MobbIconMarkdown = ``;
|
|
3576
|
+
var noVulnerabilitiesFoundTitle = `# ${MobbIconMarkdown} No security issues were found \u2705`;
|
|
3306
3577
|
function scannerToFriendlyString(scanner) {
|
|
3307
3578
|
switch (scanner) {
|
|
3308
3579
|
case "checkmarx":
|
|
@@ -3315,7 +3586,7 @@ function scannerToFriendlyString(scanner) {
|
|
|
3315
3586
|
return "Snyk";
|
|
3316
3587
|
}
|
|
3317
3588
|
}
|
|
3318
|
-
async function
|
|
3589
|
+
async function getRelevantVulenrabilitiesFromDiff(params) {
|
|
3319
3590
|
const { gqlClient, diff, vulnerabilityReportId } = params;
|
|
3320
3591
|
const parsedDiff = parseDiff(diff);
|
|
3321
3592
|
const fileHunks = parsedDiff.map((file) => {
|
|
@@ -3338,13 +3609,45 @@ async function getFixesFromDiff(params) {
|
|
|
3338
3609
|
vulnerabilityReportId
|
|
3339
3610
|
});
|
|
3340
3611
|
}
|
|
3612
|
+
async function getFixesData(params) {
|
|
3613
|
+
const { gqlClient, fixesId } = params;
|
|
3614
|
+
const { fixes } = await gqlClient.getFixes(fixesId);
|
|
3615
|
+
return keyBy(fixes, "id");
|
|
3616
|
+
}
|
|
3617
|
+
function buildAnalysisSummaryComment(params) {
|
|
3618
|
+
const { prVulenrabilities: fixesFromDiff, fixesById } = params;
|
|
3619
|
+
const { vulnerabilityReportIssueCodeNodes, fixablePrVuls } = fixesFromDiff;
|
|
3620
|
+
const title = `# ${MobbIconMarkdown} ${fixablePrVuls} ${fixablePrVuls === 1 ? "fix is" : "fixes are"} ready to be committed`;
|
|
3621
|
+
const summary = Object.entries(
|
|
3622
|
+
// count every issue type
|
|
3623
|
+
vulnerabilityReportIssueCodeNodes.reduce(
|
|
3624
|
+
(result, vulnerabilityReportIssueCodeNode) => {
|
|
3625
|
+
const { vulnerabilityReportIssue } = vulnerabilityReportIssueCodeNode;
|
|
3626
|
+
const fix = fixesById[vulnerabilityReportIssue.fixId];
|
|
3627
|
+
if (!fix) {
|
|
3628
|
+
throw new Error(`fix ${vulnerabilityReportIssue.fixId} not found`);
|
|
3629
|
+
}
|
|
3630
|
+
const issueType = getIssueType(fix.issueType);
|
|
3631
|
+
const vulnerabilityReportIssueCount = (result[issueType] || 0) + 1;
|
|
3632
|
+
return {
|
|
3633
|
+
...result,
|
|
3634
|
+
[issueType]: vulnerabilityReportIssueCount
|
|
3635
|
+
};
|
|
3636
|
+
},
|
|
3637
|
+
{}
|
|
3638
|
+
)
|
|
3639
|
+
).map(([issueType, issueTypeCount]) => `**${issueType}** - ${issueTypeCount}`);
|
|
3640
|
+
return `${title}
|
|
3641
|
+
${summary.join("\n")}`;
|
|
3642
|
+
}
|
|
3341
3643
|
async function handleFinishedAnalysis({
|
|
3342
3644
|
analysisId,
|
|
3343
3645
|
scm: _scm,
|
|
3344
3646
|
gqlClient,
|
|
3345
|
-
|
|
3647
|
+
githubActionToken,
|
|
3346
3648
|
scanner
|
|
3347
3649
|
}) {
|
|
3650
|
+
const githubActionOctokit = new Octokit3({ auth: githubActionToken });
|
|
3348
3651
|
if (_scm instanceof GithubSCMLib === false) {
|
|
3349
3652
|
return;
|
|
3350
3653
|
}
|
|
@@ -3358,17 +3661,59 @@ async function handleFinishedAnalysis({
|
|
|
3358
3661
|
} = getAnalysis.analysis;
|
|
3359
3662
|
const { commitSha, pullRequest } = getAnalysis.analysis.repo;
|
|
3360
3663
|
const diff = await scm.getPrDiff({ pull_number: pullRequest });
|
|
3361
|
-
const
|
|
3664
|
+
const prVulenrabilities = await getRelevantVulenrabilitiesFromDiff({
|
|
3362
3665
|
diff,
|
|
3363
3666
|
gqlClient,
|
|
3364
3667
|
vulnerabilityReportId: getAnalysis.analysis.vulnerabilityReportId
|
|
3365
3668
|
});
|
|
3366
|
-
const
|
|
3367
|
-
|
|
3368
|
-
|
|
3669
|
+
const { vulnerabilityReportIssueCodeNodes } = prVulenrabilities;
|
|
3670
|
+
const fixesId = vulnerabilityReportIssueCodeNodes.map(
|
|
3671
|
+
({ vulnerabilityReportIssue: { fixId } }) => fixId
|
|
3369
3672
|
);
|
|
3370
|
-
await
|
|
3371
|
-
|
|
3673
|
+
const fixesById = await getFixesData({ fixesId, gqlClient });
|
|
3674
|
+
const [comments, generalPrComments] = await Promise.all([
|
|
3675
|
+
scm.getPrComments({ pull_number: pullRequest }, githubActionOctokit),
|
|
3676
|
+
scm.getGeneralPrComments(
|
|
3677
|
+
{ prNumber: pullRequest },
|
|
3678
|
+
{ authToken: githubActionToken }
|
|
3679
|
+
)
|
|
3680
|
+
]);
|
|
3681
|
+
async function postAnalysisSummary() {
|
|
3682
|
+
if (Object.values(fixesById).length === 0) {
|
|
3683
|
+
return;
|
|
3684
|
+
}
|
|
3685
|
+
const analysisSummaryComment = buildAnalysisSummaryComment({
|
|
3686
|
+
fixesById,
|
|
3687
|
+
prVulenrabilities
|
|
3688
|
+
});
|
|
3689
|
+
await scm.postGeneralPrComment(
|
|
3690
|
+
{
|
|
3691
|
+
body: analysisSummaryComment,
|
|
3692
|
+
prNumber: pullRequest
|
|
3693
|
+
},
|
|
3694
|
+
{ authToken: githubActionToken }
|
|
3695
|
+
);
|
|
3696
|
+
}
|
|
3697
|
+
function deleteAllPreviousGeneralPrComments() {
|
|
3698
|
+
return generalPrComments.data.filter((comment) => {
|
|
3699
|
+
if (!comment.body) {
|
|
3700
|
+
return false;
|
|
3701
|
+
}
|
|
3702
|
+
return comment.body.includes(MOBB_ICON_IMG);
|
|
3703
|
+
}).map((comment) => {
|
|
3704
|
+
try {
|
|
3705
|
+
return scm.deleteGeneralPrComment(
|
|
3706
|
+
{ commentId: comment.id },
|
|
3707
|
+
{ authToken: githubActionToken }
|
|
3708
|
+
);
|
|
3709
|
+
} catch (e) {
|
|
3710
|
+
debug4("delete comment failed %s", e);
|
|
3711
|
+
return Promise.resolve();
|
|
3712
|
+
}
|
|
3713
|
+
});
|
|
3714
|
+
}
|
|
3715
|
+
function deleteAllPreviousComments() {
|
|
3716
|
+
return comments.data.filter((comment) => {
|
|
3372
3717
|
return comment.body.includes(MOBB_ICON_IMG);
|
|
3373
3718
|
}).map((comment) => {
|
|
3374
3719
|
try {
|
|
@@ -3380,70 +3725,154 @@ async function handleFinishedAnalysis({
|
|
|
3380
3725
|
debug4("delete comment failed %s", e);
|
|
3381
3726
|
return Promise.resolve();
|
|
3382
3727
|
}
|
|
3383
|
-
})
|
|
3384
|
-
|
|
3385
|
-
|
|
3386
|
-
|
|
3387
|
-
|
|
3388
|
-
|
|
3389
|
-
|
|
3390
|
-
|
|
3391
|
-
|
|
3392
|
-
|
|
3393
|
-
|
|
3394
|
-
|
|
3395
|
-
|
|
3396
|
-
|
|
3397
|
-
|
|
3398
|
-
|
|
3399
|
-
|
|
3400
|
-
|
|
3401
|
-
|
|
3402
|
-
|
|
3403
|
-
|
|
3404
|
-
|
|
3405
|
-
|
|
3406
|
-
|
|
3407
|
-
|
|
3408
|
-
|
|
3409
|
-
|
|
3410
|
-
|
|
3411
|
-
|
|
3412
|
-
|
|
3413
|
-
|
|
3414
|
-
|
|
3415
|
-
|
|
3416
|
-
|
|
3417
|
-
|
|
3418
|
-
|
|
3419
|
-
|
|
3420
|
-
|
|
3421
|
-
|
|
3422
|
-
|
|
3423
|
-
|
|
3424
|
-
|
|
3425
|
-
|
|
3426
|
-
|
|
3427
|
-
|
|
3728
|
+
});
|
|
3729
|
+
}
|
|
3730
|
+
await Promise.all([
|
|
3731
|
+
...deleteAllPreviousComments(),
|
|
3732
|
+
...deleteAllPreviousGeneralPrComments()
|
|
3733
|
+
]);
|
|
3734
|
+
async function postFixComment(vulnerabilityReportIssueCodeNode) {
|
|
3735
|
+
const {
|
|
3736
|
+
path: path9,
|
|
3737
|
+
startLine,
|
|
3738
|
+
vulnerabilityReportIssue: { fixId }
|
|
3739
|
+
} = vulnerabilityReportIssueCodeNode;
|
|
3740
|
+
const fix = fixesById[fixId];
|
|
3741
|
+
if (!fix) {
|
|
3742
|
+
throw new Error(`fix ${fixId} not found`);
|
|
3743
|
+
}
|
|
3744
|
+
const {
|
|
3745
|
+
patchAndQuestions: { patch }
|
|
3746
|
+
} = fix;
|
|
3747
|
+
const commentRes = await scm.postPrComment(
|
|
3748
|
+
{
|
|
3749
|
+
body: "empty",
|
|
3750
|
+
pull_number: pullRequest,
|
|
3751
|
+
commit_id: commitSha,
|
|
3752
|
+
path: path9,
|
|
3753
|
+
line: startLine
|
|
3754
|
+
},
|
|
3755
|
+
githubActionOctokit
|
|
3756
|
+
);
|
|
3757
|
+
const commentId = commentRes.data.id;
|
|
3758
|
+
const commitUrl = getCommitUrl({
|
|
3759
|
+
appBaseUrl: WEB_APP_URL,
|
|
3760
|
+
fixId,
|
|
3761
|
+
projectId,
|
|
3762
|
+
analysisId,
|
|
3763
|
+
organizationId,
|
|
3764
|
+
redirectUrl: commentRes.data.html_url,
|
|
3765
|
+
commentId
|
|
3766
|
+
});
|
|
3767
|
+
const fixUrl = getFixUrlWithRedirect({
|
|
3768
|
+
appBaseUrl: WEB_APP_URL,
|
|
3769
|
+
fixId,
|
|
3770
|
+
projectId,
|
|
3771
|
+
analysisId,
|
|
3772
|
+
organizationId,
|
|
3773
|
+
redirectUrl: commentRes.data.html_url,
|
|
3774
|
+
commentId
|
|
3775
|
+
});
|
|
3776
|
+
const scanerString = scannerToFriendlyString(scanner);
|
|
3777
|
+
const issueType = getIssueType(fix.issueType);
|
|
3778
|
+
const title = `# ${MobbIconMarkdown} ${issueType} fix is ready`;
|
|
3779
|
+
const subTitle = `### Apply the following code change to fix ${issueType} issue detected by **${scanerString}**:`;
|
|
3780
|
+
const diff2 = `\`\`\`diff
|
|
3428
3781
|
${patch}
|
|
3429
3782
|
\`\`\``;
|
|
3430
|
-
|
|
3431
|
-
|
|
3432
|
-
|
|
3433
|
-
|
|
3783
|
+
const fixPageLink = `[Learn more and fine tune the fix](${fixUrl})`;
|
|
3784
|
+
await scm.updatePrComment(
|
|
3785
|
+
{
|
|
3786
|
+
body: `${title}
|
|
3434
3787
|
${subTitle}
|
|
3435
3788
|
${diff2}
|
|
3436
3789
|
${commitFixButton(
|
|
3437
|
-
|
|
3438
|
-
|
|
3790
|
+
commitUrl
|
|
3791
|
+
)}
|
|
3439
3792
|
${fixPageLink}`,
|
|
3440
|
-
|
|
3441
|
-
|
|
3442
|
-
|
|
3443
|
-
|
|
3444
|
-
|
|
3445
|
-
|
|
3446
|
-
|
|
3793
|
+
comment_id: commentId
|
|
3794
|
+
},
|
|
3795
|
+
githubActionOctokit
|
|
3796
|
+
);
|
|
3797
|
+
}
|
|
3798
|
+
async function postAnalysisInsightComment() {
|
|
3799
|
+
const scanerString = scannerToFriendlyString(scanner);
|
|
3800
|
+
const {
|
|
3801
|
+
totalPrVulnerabilities,
|
|
3802
|
+
vulnerabilitiesOutsidePr,
|
|
3803
|
+
fixablePrVuls,
|
|
3804
|
+
nonFixablePrVuls
|
|
3805
|
+
} = prVulenrabilities;
|
|
3806
|
+
debug4({
|
|
3807
|
+
fixablePrVuls,
|
|
3808
|
+
nonFixablePrVuls,
|
|
3809
|
+
vulnerabilitiesOutsidePr,
|
|
3810
|
+
totalPrVulnerabilities
|
|
3811
|
+
});
|
|
3812
|
+
if (totalPrVulnerabilities === 0 && vulnerabilitiesOutsidePr === 0) {
|
|
3813
|
+
const body = `Awesome! No vulnerabilities were found by **${scanerString}**`;
|
|
3814
|
+
const noVulsFoundComment = `${noVulnerabilitiesFoundTitle}
|
|
3815
|
+
${body}`;
|
|
3816
|
+
await scm.postGeneralPrComment(
|
|
3817
|
+
{
|
|
3818
|
+
body: noVulsFoundComment,
|
|
3819
|
+
prNumber: pullRequest
|
|
3820
|
+
},
|
|
3821
|
+
{ authToken: githubActionToken }
|
|
3822
|
+
);
|
|
3823
|
+
return;
|
|
3824
|
+
}
|
|
3825
|
+
if (totalPrVulnerabilities === 0 && vulnerabilitiesOutsidePr > 0) {
|
|
3826
|
+
const body = `Awesome! No vulnerabilities were found by **${scanerString}** in the changes made as part of this PR.`;
|
|
3827
|
+
const body2 = `Please notice there are issues in this repo that are unrelated to this PR.`;
|
|
3828
|
+
const noVulsFoundComment = `${noVulnerabilitiesFoundTitle}
|
|
3829
|
+
${body}
|
|
3830
|
+
${body2}`;
|
|
3831
|
+
await scm.postGeneralPrComment(
|
|
3832
|
+
{
|
|
3833
|
+
body: noVulsFoundComment,
|
|
3834
|
+
prNumber: pullRequest
|
|
3835
|
+
},
|
|
3836
|
+
{ authToken: githubActionToken }
|
|
3837
|
+
);
|
|
3838
|
+
return;
|
|
3839
|
+
}
|
|
3840
|
+
if (fixablePrVuls === 0 && nonFixablePrVuls > 0) {
|
|
3841
|
+
const title = `# ${MobbIconMarkdown} We couldn't fix the issues detected by **${scanerString}**`;
|
|
3842
|
+
const body = `Mobb Fixer gets better and better every day, but unfortunately your current issues aren't supported yet.`;
|
|
3843
|
+
const noFixableVulsComment = `${title}
|
|
3844
|
+
${body}
|
|
3845
|
+
${contactUsMarkdown}`;
|
|
3846
|
+
await scm.postGeneralPrComment(
|
|
3847
|
+
{
|
|
3848
|
+
body: noFixableVulsComment,
|
|
3849
|
+
prNumber: pullRequest
|
|
3850
|
+
},
|
|
3851
|
+
{ authToken: githubActionToken }
|
|
3852
|
+
);
|
|
3853
|
+
return;
|
|
3854
|
+
}
|
|
3855
|
+
if (fixablePrVuls < nonFixablePrVuls && fixablePrVuls > 0) {
|
|
3856
|
+
const title = `# ${MobbIconMarkdown} We couldn't fix some of the issues detected by **${scanerString}**`;
|
|
3857
|
+
const body = "Mobb Fixer gets better and better every day, but unfortunately your current issues aren't supported yet.";
|
|
3858
|
+
const fixableVulsComment = `${title}
|
|
3859
|
+
${body}
|
|
3860
|
+
${contactUsMarkdown}`;
|
|
3861
|
+
await scm.postGeneralPrComment(
|
|
3862
|
+
{
|
|
3863
|
+
body: fixableVulsComment,
|
|
3864
|
+
prNumber: pullRequest
|
|
3865
|
+
},
|
|
3866
|
+
{ authToken: githubActionToken }
|
|
3867
|
+
);
|
|
3868
|
+
return;
|
|
3869
|
+
}
|
|
3870
|
+
}
|
|
3871
|
+
await Promise.all([
|
|
3872
|
+
...prVulenrabilities.vulnerabilityReportIssueCodeNodes.map(postFixComment),
|
|
3873
|
+
postAnalysisInsightComment(),
|
|
3874
|
+
postAnalysisSummary()
|
|
3875
|
+
]);
|
|
3447
3876
|
}
|
|
3448
3877
|
|
|
3449
3878
|
// src/features/analysis/pack.ts
|
|
@@ -3913,11 +4342,8 @@ async function runAnalysis(params, options) {
|
|
|
3913
4342
|
tmpObj.removeCallback();
|
|
3914
4343
|
}
|
|
3915
4344
|
}
|
|
3916
|
-
function
|
|
3917
|
-
scmLibType
|
|
3918
|
-
githubToken,
|
|
3919
|
-
gitlabToken,
|
|
3920
|
-
adoToken
|
|
4345
|
+
function _getUrlForScmType({
|
|
4346
|
+
scmLibType
|
|
3921
4347
|
}) {
|
|
3922
4348
|
const githubAuthUrl = `${WEB_APP_URL}/github-auth`;
|
|
3923
4349
|
const gitlabAuthUrl = `${WEB_APP_URL}/gitlab-auth`;
|
|
@@ -3925,22 +4351,18 @@ function _getTokenAndUrlForScmType({
|
|
|
3925
4351
|
switch (scmLibType) {
|
|
3926
4352
|
case "GITHUB" /* GITHUB */:
|
|
3927
4353
|
return {
|
|
3928
|
-
token: githubToken,
|
|
3929
4354
|
authUrl: githubAuthUrl
|
|
3930
4355
|
};
|
|
3931
4356
|
case "GITLAB" /* GITLAB */:
|
|
3932
4357
|
return {
|
|
3933
|
-
token: gitlabToken,
|
|
3934
4358
|
authUrl: gitlabAuthUrl
|
|
3935
4359
|
};
|
|
3936
4360
|
case "ADO" /* ADO */:
|
|
3937
4361
|
return {
|
|
3938
|
-
token: adoToken,
|
|
3939
4362
|
authUrl: adoAuthUrl
|
|
3940
4363
|
};
|
|
3941
4364
|
default:
|
|
3942
4365
|
return {
|
|
3943
|
-
token: void 0,
|
|
3944
4366
|
authUrl: void 0
|
|
3945
4367
|
};
|
|
3946
4368
|
}
|
|
@@ -3983,35 +4405,34 @@ async function _scan(params, { skipPrompts = false } = {}) {
|
|
|
3983
4405
|
throw new Error("repo is required in case srcPath is not provided");
|
|
3984
4406
|
}
|
|
3985
4407
|
const userInfo = await gqlClient.getUserInfo();
|
|
3986
|
-
const
|
|
4408
|
+
const tokenInfo = getScmConfig({
|
|
4409
|
+
url: repo,
|
|
4410
|
+
scmConfigs: userInfo.scmConfigs,
|
|
4411
|
+
includeOrgTokens: false
|
|
4412
|
+
});
|
|
3987
4413
|
const isRepoAvailable = await scmCanReachRepo({
|
|
3988
4414
|
repoUrl: repo,
|
|
3989
|
-
|
|
3990
|
-
|
|
3991
|
-
|
|
3992
|
-
scmOrg: adoOrg
|
|
4415
|
+
accessToken: tokenInfo.accessToken,
|
|
4416
|
+
scmOrg: tokenInfo.scmOrg,
|
|
4417
|
+
scmType: getScmTypeFromScmLibType(tokenInfo.scmLibType)
|
|
3993
4418
|
});
|
|
3994
|
-
const
|
|
3995
|
-
const { authUrl: scmAuthUrl
|
|
3996
|
-
scmLibType
|
|
3997
|
-
githubToken,
|
|
3998
|
-
gitlabToken,
|
|
3999
|
-
adoToken
|
|
4419
|
+
const cloudScmLibType = getCloudScmLibTypeFromUrl(repo);
|
|
4420
|
+
const { authUrl: scmAuthUrl } = _getUrlForScmType({
|
|
4421
|
+
scmLibType: cloudScmLibType
|
|
4000
4422
|
});
|
|
4001
|
-
let myToken =
|
|
4423
|
+
let myToken = tokenInfo.accessToken;
|
|
4002
4424
|
if (!isRepoAvailable) {
|
|
4003
|
-
if (ci || !
|
|
4425
|
+
if (ci || !cloudScmLibType || !scmAuthUrl) {
|
|
4004
4426
|
const errorMessage = scmAuthUrl ? `Cannot access repo ${repo}` : `Cannot access repo ${repo} with the provided token, please visit ${scmAuthUrl} to refresh your source control management system token`;
|
|
4005
4427
|
throw new Error(errorMessage);
|
|
4006
4428
|
}
|
|
4007
|
-
if (
|
|
4008
|
-
myToken = await handleScmIntegration(
|
|
4429
|
+
if (cloudScmLibType && scmAuthUrl) {
|
|
4430
|
+
myToken = await handleScmIntegration(tokenInfo.accessToken, scmAuthUrl, repo) || "";
|
|
4009
4431
|
const isRepoAvailable2 = await scmCanReachRepo({
|
|
4010
4432
|
repoUrl: repo,
|
|
4011
|
-
|
|
4012
|
-
|
|
4013
|
-
|
|
4014
|
-
scmOrg: adoOrg
|
|
4433
|
+
accessToken: myToken,
|
|
4434
|
+
scmOrg: tokenInfo.scmOrg,
|
|
4435
|
+
scmType: getScmTypeFromScmLibType(tokenInfo.scmLibType)
|
|
4015
4436
|
});
|
|
4016
4437
|
if (!isRepoAvailable2) {
|
|
4017
4438
|
throw new Error(
|
|
@@ -4022,9 +4443,9 @@ async function _scan(params, { skipPrompts = false } = {}) {
|
|
|
4022
4443
|
}
|
|
4023
4444
|
const scm = await SCMLib.init({
|
|
4024
4445
|
url: repo,
|
|
4025
|
-
accessToken:
|
|
4026
|
-
|
|
4027
|
-
|
|
4446
|
+
accessToken: myToken,
|
|
4447
|
+
scmOrg: tokenInfo.scmOrg,
|
|
4448
|
+
scmType: tokenInfo.scmLibType
|
|
4028
4449
|
});
|
|
4029
4450
|
const reference = ref ?? await scm.getRepoDefaultBranch();
|
|
4030
4451
|
const { sha } = await scm.getReferenceData(reference);
|
|
@@ -4066,7 +4487,7 @@ async function _scan(params, { skipPrompts = false } = {}) {
|
|
|
4066
4487
|
analysisId,
|
|
4067
4488
|
gqlClient,
|
|
4068
4489
|
scm,
|
|
4069
|
-
|
|
4490
|
+
githubActionToken: z10.string().parse(githubActionToken),
|
|
4070
4491
|
scanner: z10.nativeEnum(SCANNERS).parse(scanner)
|
|
4071
4492
|
})
|
|
4072
4493
|
);
|
|
@@ -4196,8 +4617,9 @@ async function _scan(params, { skipPrompts = false } = {}) {
|
|
|
4196
4617
|
throw new CliError2();
|
|
4197
4618
|
}
|
|
4198
4619
|
}
|
|
4199
|
-
async function handleScmIntegration(oldToken,
|
|
4200
|
-
const
|
|
4620
|
+
async function handleScmIntegration(oldToken, scmAuthUrl2, repoUrl) {
|
|
4621
|
+
const scmLibType = getCloudScmLibTypeFromUrl(repoUrl);
|
|
4622
|
+
const scmName = scmLibType === "GITHUB" /* GITHUB */ ? "Github" : scmLibType === "GITLAB" /* GITLAB */ ? "Gitlab" : scmLibType === "ADO" /* ADO */ ? "Azure DevOps" : "";
|
|
4201
4623
|
const addScmIntegration = skipPrompts ? true : await scmIntegrationPrompt(scmName);
|
|
4202
4624
|
const scmSpinner = createSpinner4(
|
|
4203
4625
|
`\u{1F517} Waiting for ${scmName} integration...`
|
|
@@ -4211,14 +4633,15 @@ async function _scan(params, { skipPrompts = false } = {}) {
|
|
|
4211
4633
|
);
|
|
4212
4634
|
await open2(scmAuthUrl2);
|
|
4213
4635
|
for (let i = 0; i < LOGIN_MAX_WAIT / LOGIN_CHECK_DELAY; i++) {
|
|
4214
|
-
const
|
|
4215
|
-
|
|
4216
|
-
|
|
4217
|
-
|
|
4218
|
-
|
|
4219
|
-
|
|
4220
|
-
|
|
4221
|
-
|
|
4636
|
+
const userInfo2 = await gqlClient.getUserInfo();
|
|
4637
|
+
const tokenInfo2 = getScmConfig({
|
|
4638
|
+
url: repoUrl,
|
|
4639
|
+
scmConfigs: userInfo2.scmConfigs,
|
|
4640
|
+
includeOrgTokens: false
|
|
4641
|
+
});
|
|
4642
|
+
if (tokenInfo2.accessToken && tokenInfo2.accessToken !== oldToken) {
|
|
4643
|
+
scmSpinner.success({ text: `\u{1F517} ${scmName} integration successful!` });
|
|
4644
|
+
return tokenInfo2.accessToken;
|
|
4222
4645
|
}
|
|
4223
4646
|
scmSpinner.spin();
|
|
4224
4647
|
await sleep(LOGIN_CHECK_DELAY);
|
|
@@ -4373,12 +4796,16 @@ var packageJson2 = JSON.parse(
|
|
|
4373
4796
|
);
|
|
4374
4797
|
var config3 = new Configstore2(packageJson2.name, { apiToken: "" });
|
|
4375
4798
|
async function addScmToken(addScmTokenOptions) {
|
|
4376
|
-
const { apiKey, token, organization,
|
|
4799
|
+
const { apiKey, token, organization, scmType, url, username, refreshToken } = addScmTokenOptions;
|
|
4377
4800
|
const gqlClient = new GQLClient({
|
|
4378
4801
|
apiKey: apiKey || config3.get("apiToken")
|
|
4379
4802
|
});
|
|
4803
|
+
if (!scmType) {
|
|
4804
|
+
throw new CliError(errorMessages.invalidScmType);
|
|
4805
|
+
}
|
|
4380
4806
|
await gqlClient.updateScmToken({
|
|
4381
|
-
|
|
4807
|
+
scmType,
|
|
4808
|
+
url,
|
|
4382
4809
|
token,
|
|
4383
4810
|
org: organization,
|
|
4384
4811
|
username,
|
|
@@ -4462,9 +4889,16 @@ var commitHashOption = {
|
|
|
4462
4889
|
type: "string"
|
|
4463
4890
|
};
|
|
4464
4891
|
var scmTypeOption = {
|
|
4892
|
+
demandOption: true,
|
|
4465
4893
|
describe: chalk5.bold("SCM type (GitHub, GitLab, Ado)"),
|
|
4466
4894
|
type: "string"
|
|
4467
4895
|
};
|
|
4896
|
+
var urlOption = {
|
|
4897
|
+
describe: chalk5.bold(
|
|
4898
|
+
"URL of the repository (used in GitHub, GitLab, Azure DevOps)"
|
|
4899
|
+
),
|
|
4900
|
+
type: "string"
|
|
4901
|
+
};
|
|
4468
4902
|
var scmOrgOption = {
|
|
4469
4903
|
describe: chalk5.bold("Organization name in SCM (used in Azure DevOps)"),
|
|
4470
4904
|
type: "string"
|
|
@@ -4651,29 +5085,32 @@ async function scanHandler(args) {
|
|
|
4651
5085
|
|
|
4652
5086
|
// src/args/commands/token.ts
|
|
4653
5087
|
function addScmTokenBuilder(args) {
|
|
4654
|
-
return args.option("scm", scmTypeOption).option("token", scmTokenOption).option("organization", scmOrgOption).option("username", scmUsernameOption).option("refresh-token", scmRefreshTokenOption).option("api-key", apiKeyOption).example(
|
|
4655
|
-
"$0 add-scm-token --scm
|
|
5088
|
+
return args.option("scm-type", scmTypeOption).option("url", urlOption).option("token", scmTokenOption).option("organization", scmOrgOption).option("username", scmUsernameOption).option("refresh-token", scmRefreshTokenOption).option("api-key", apiKeyOption).example(
|
|
5089
|
+
"$0 add-scm-token --scm-type Ado --url https://dev.azure.com/adoorg/test/_git/repo --token abcdef0123456 --organization myOrg",
|
|
4656
5090
|
"Add your SCM (Github, Gitlab, Azure DevOps) token to Mobb to enable automated fixes."
|
|
4657
|
-
).help().demandOption(["
|
|
5091
|
+
).help().demandOption(["url", "token"]);
|
|
4658
5092
|
}
|
|
4659
5093
|
function validateAddScmTokenOptions(argv) {
|
|
4660
|
-
if (!argv.
|
|
4661
|
-
throw new CliError(errorMessages.
|
|
4662
|
-
}
|
|
4663
|
-
if (!Object.values(ScmTypes).includes(argv.scm)) {
|
|
4664
|
-
throw new CliError(errorMessages.invalidScmType);
|
|
5094
|
+
if (!argv.url) {
|
|
5095
|
+
throw new CliError(errorMessages.missingUrl);
|
|
4665
5096
|
}
|
|
4666
5097
|
if (!argv.token) {
|
|
4667
5098
|
throw new CliError(errorMessages.missingToken);
|
|
4668
5099
|
}
|
|
4669
|
-
if (argv.
|
|
5100
|
+
if ("GitHub" /* GitHub */ !== argv.scmType && "Ado" /* Ado */ !== argv.scmType && "GitLab" /* GitLab */ !== argv.scmType) {
|
|
4670
5101
|
throw new CliError(
|
|
4671
|
-
"\nError: --
|
|
5102
|
+
"\nError: --scm-type must reference a valid SCM type (GitHub, GitLab, Ado)"
|
|
4672
5103
|
);
|
|
4673
5104
|
}
|
|
4674
|
-
|
|
5105
|
+
const urlObj = new URL(argv.url);
|
|
5106
|
+
if (urlObj.hostname === "github.com" && !argv.username) {
|
|
4675
5107
|
throw new CliError("\nError: --username flag is required for GitHub");
|
|
4676
5108
|
}
|
|
5109
|
+
if ((urlObj.hostname === "dev.azure.com" || urlObj.hostname.endsWith(".visualstudio.com")) && !argv.organization) {
|
|
5110
|
+
throw new CliError(
|
|
5111
|
+
"\nError: --organization flag is required for Azure DevOps"
|
|
5112
|
+
);
|
|
5113
|
+
}
|
|
4677
5114
|
}
|
|
4678
5115
|
async function addScmTokenHandler(args) {
|
|
4679
5116
|
validateAddScmTokenOptions(args);
|